package com.example.parametervalidator.validator.core.processor;


import com.example.parametervalidator.entity.ParameterBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;

/**
 * 注解解析器的责任链模式+模板方法模式
 */
public abstract class AbstractAnnotationProcessor implements AnnotationProcessor {


    //责任链
    @Autowired
    private List<AnnotationProcessor> annotationProcessors;

    protected ParameterBean parameterBean;


    protected final boolean contains(AnnotationProcessor annotationProcessor) {
        return annotationProcessors.contains(annotationProcessor);
    }

    protected final void remove(AnnotationProcessor annotationProcessor) {
        this.annotationProcessors.remove(annotationProcessor);
    }

    /**
     * 解析约束注解
     *
     * @param clazz
     * @param target
     * @return
     * @throws Exception
     */
    public final ParameterBean analysisAnnotation(Class clazz, Object target) {
        // 获取实体类的所有属性，返回Field数组
        try {
            Field[] fields = clazz.getDeclaredFields();
            if (fields != null && fields.length > 0) {//拥有字段
                for (Field field :
                        fields) {
                    //如果是 基本数据类型。需要判断基本数据类型和包装类型。
                    //验证是否为空。
                    if (this.parameterBean == null) {
                        //初始化ParameterBean实体
                        this.parameterBeanInstantiate(clazz);
                    }
                    invokAnalysisAnnotationProcessor(clazz, target, field);
                }
            }
            return this.parameterBean;
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } finally {
            this.parameterBean = null;
        }
        return null;
    }

    /**
     * 初始化ParameterBean实体，
     *
     * @param clazz 需要封装ParameterBean的参数对象。
     */
    private final void parameterBeanInstantiate(Class clazz) {
        this.parameterBean = new ParameterBean();
        this.parameterBean.setParams(new HashMap<>());
        this.parameterBean.setClassName(clazz.getTypeName());
    }


    public static String getBooleanPrefix(String fieldName) {
        String prefix = fieldName.substring(0, 2);
        System.out.println(prefix);
        if (prefix.equals("is")) {
            return fieldName;
        } else {
            return "is" + getMethodName(fieldName);
        }
    }


    protected final String getAnnotationType(String className) {
        if (className.contains(".")) {
            return className.substring(className.lastIndexOf(".") + 1);
        } else {
            return className;
        }
    }


    // 把一个字符串的第一个字母大写、效率是最高的、
    public static final String getMethodName(String fildeName) {
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }


    private int index = 0;

    private final boolean hasNext() {
        if (index < annotationProcessors.size() && index > -1) {//还有下一个
            return true;//返回true，告诉子类，拥有下一个。
        } else {//没有下一个了。那么index应该归为虚无。-1
            index = 0;
            return false;
        }
    }


    /**
     * 调用链调度器
     *
     * @param clazz
     * @param target
     * @param field
     */
    private void invokAnalysisAnnotationProcessor(Class clazz, Object target, Field field) {
        //拥有下一个，那么久调用下一个。
        try {
            while (hasNext()) {
                this.annotationProcessors.get(index).analysisAnnotation(target, field,this.parameterBean);
                index++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            index = 0;
        }

    }



}
